Jan. 2023
# 1. CONCEPTS
# 1. CONCEPTS
# in mod_add.py
def add(a, b):
return a+b
# in my_script.py
def add(a, b):
return a+b
result = add(30,12)
print(result)
Script
Module
# 1. CONCEPTS
# in mod_add.py
def add(a, b):
return a+b
# in my_script.py
from mod_add import add
result = add(30,12)
print(result)
Script
Module
# 1. CONCEPTS
Script
Module
# in (exec.) mod_add.py
def add(a, b):
return a+b
if __name__ == "__main__":
result = add(30,12)
print(result)
# in my_script.py
from mod_add import add
result = add(30,12)
print(result)
# 1. CONCEPTS
# 1. CONCEPTS
# 1. CONCEPTS
Collection of modules & packages
What are Python Libraries
# 1. CONCEPTS
What are Python Libraries
# 1. CONCEPTS
# 1. CONCEPTS
# 2. PACKAGING FLOW
# 2. PACKAGING FLOW
Develop & Configure a Python Package
- Create your Source Tree
- Package configuration file
Build & Distribute a Python Package
- Build Artifacts (source distribution, built distribution)
- Upload to the package distribution service (PyPi, Artifactory, ...)
- Binaries & Dependencies
Download & Install
# 2. PACKAGING FLOW
Packaging Demystified
# 3. DEMO PACKAGE
The Gregory-Leibniz Series
(proof: @stanford.edu)
cf. Packaging Demystified
# 3. DEMO PACKAGE
Create your Source Tree (folders, subfolders, files) with Poetry
➜ poetry new approx_pi
Created package approx_pi in approx_pi
➜ tree approx_pi/
approx_pi
├── README.md
├── approx_pi
│ └── __init__.py
├── pyproject.toml
└── tests
└── __init__.py
2 directories, 4 files
# 3. DEMO PACKAGE
# pi_approx.py
from math import pi
def approximate_pi(iteration_count: int) -> float:
sign, result = 1, 0.0
for at in range(iteration_count):
result += sign / (2 * at + 1)
sign *= -1
return result * 4
if __name__ == "__main__":
approx_1, approx_2 = approximate_pi(300), approximate_pi(301)
print(f"approx 300 {approx_1} with diff {approx_1 - pi}")
print(f"approx 301 {approx_2} with diff {approx_2 - pi}")
Add functionalities to your main module
pi_approx.py
# 3. DEMO PACKAGE
➜ # Activating the virtual environment
➜ poetry shell
Spawning shell within /home/patricme/.cache/pypoetry/virtualenvs/approx-pi-BE-Xuvxi-py3.9
➜ . /home/patricme/.cache/pypoetry/virtualenvs/approx-pi-BE-Xuvxi-py3.9/bin/activate
(approx-pi-py3.9)
➜ # Installing dependencies
➜ poetry install
Creating virtualenv approx-pi-BE-Xuvxi-py3.9 in /home/patricme/.cache/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies... (0.1s)
Writing lock file
Create a local environment & Install dependencies (Poetry)
# 3. DEMO PACKAGE
# Running a python script
(approx-pi-py3.9) ➜ python3 approx_pi/pi_approx.py
approx 300 3.1382593295155914 with diff -0.0033333240742017267
approx 301 3.1449149035588526 with diff 0.0033222499690594987
# Running a python module
(approx-pi-py3.9) ➜ python3 -m approx_pi.pi_approx
approx 300 3.1382593295155914 with diff -0.0033333240742017267
approx 301 3.1449149035588526 with diff 0.0033222499690594987
# 3. DEMO PACKAGE
Running your Python package
(approx-pi-py3.9) ➜ poetry add cowsay
Using version ^5.0 for cowsay
Updating dependencies
Resolving dependencies... (9.2s)
Writing lock file
Package operations: 1 install, 0 updates, 0 removals
• Installing cowsay (5.0)
# pi_approx.py
...
if __name__ == "__main__":
approx_1, approx_2 = approximate_pi(300), approximate_pi(301)
print(f"approx 300 {approx_1} with diff {approx_1 - pi}")
print(f"approx 301 {approx_2} with diff {approx_2 - pi}")
cowsay.cow(f"The difference between \nthe approximations is \n{'%.2E' % Decimal(approx_1-approx_2)}")
# 3. DEMO PACKAGE
# pyproject.toml
[tool.poetry]
name = "approx-pi"
version = "0.1.0"
description = ""
authors = ["Patrick Merlot <patrick.merlot@gmail.com>"]
readme = "README.md"
packages = [{include = "approx_pi"}]
[tool.poetry.dependencies]
python = "^3.9"
cowsay = "^5.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
# 3. DEMO PACKAGE
Updated config file after adding the new dependency (cowsay)
(approx-pi-py3.9) ➜ python3 -m approx_pi.pi_approx
approx 300 3.1382593295155914 with diff -0.0033333240742017267
approx 301 3.1449149035588526 with diff 0.0033222499690594987
______________________
/ \
| The difference between |
| the approximations is |
| -6.66E-03 |
\ /
======================
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
# 3. DEMO PACKAGE
Running your Python package
# 4. BUILD DISTRIBTUION PACKAGE
(approx-pi-py3.9) ➜ poetry build
Building approx-pi (0.1.0)
- Building sdist
- Built approx_pi-0.1.0.tar.gz
- Building wheel
- Built approx_pi-0.1.0-py3-none-any.whl
the source distribution (sdist) & the built distribution (wheels)
# 4. BUILD DISTRIBTUION PACKAGE
# 5. PUBLISH DISTRIBTUION PACKAGE
PyPI (pypi.org) is the default publishing target for Poetry.
In order to publish a package to PyPI, you will need to create an account. Go to the official registration page in your web browser.
# 5. PUBLISH DISTRIBTUION PACKAGE
Token authentication is the recommended way to use your PyPI account in the command line.
You can use a single, automatically generated token instead of a username and password.
Enabling Token Authentication for PyPI.
# 5. PUBLISH DISTRIBTUION PACKAGE
Add your API token to Poetry with this command
➜ poetry config pypi-token.pypi <your-api-token>
Using a plaintext file to store credentials
Publishing your Python Package to PyPI
(approx-pi-py3.9) ➜ poetry publish
Publishing approx-pi (0.1.0) to PyPI
- Uploading approx_pi-0.1.0-py3-none-any.whl 100%
- Uploading approx_pi-0.1.0.tar.gz 100%
# 5. PUBLISH DISTRIBTUION PACKAGE
Check your published package in your PyPI projects, in the browser.
# 5. PUBLISH DISTRIBTUION PACKAGE
# 6. INSTALLING A PACKAGE
➜ poetry add cowsay
Using version ^5.0 for cowsay
Updating dependencies
Resolving dependencies... (9.2s)
Writing lock file
Package operations: 1 install, 0 updates, 0 removals
• Installing cowsay (5.0)
➜ poetry add <any-python-package-available-on-pypi>
# 6. INSTALLING A PACKAGE
➜ poetry add approx-pi
# 7. VERSION CONTROL
# 7. VERSION CONTROL
# Initialize your project (ONCE!)
git init
# Tell git where is the main repository (Github? Bitbucket? GitLab? ...)
# (ONCE!)
git remote add github https://github.com/Patechoc/approx_pi.git
# Specify the files that you want to add to the next "push" to the main repository
git add pyproject.toml approx_pi.py/ README.md
# Give a description to the changes you want to push
git commit -a -m "Minimum file structure for our python package"
# Push the changes that are committed to the main repository
git push
# 7. VERSION CONTROL
Create useful .gitignore files for your project
# Created by https://www.toptal.com/developers/gitignore/api/python
# Edit at https://www.toptal.com/developers/gitignore?templates=python
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml
# ruff
.ruff_cache/
# End of https://www.toptal.com/developers/gitignore/api/python
n
# 7. VERSION CONTROL
Don't save everything!
# 8. TESTING
Getting started with testing in Python
# 8. TESTING
# 9. SECURITY CHECK
Bandit is a tool designed to find common security issues in Python code.
To do this, Bandit processes each file, builds an AST from it, and runs appropriate plugins against the AST nodes. Once Bandit has finished scanning all the files, it generates a report.
# 10. CODING STANDARDS
Use isort for sorting the library imports (yes, imports have a suggested order).
Check the existence of undesired artifacts using Flake8 and Pylint.
Keep the code within the same style using Black.
Those tools can be configured to be PEP8 compliant. PEP8 — Python Enhancement Proposal, is a style guide that provides guidelines and best practices suggestions on how to write Python code.
How to write beautiful code with PEP 8
# 11. LICENSE
# 12. DOCUMENTATION
Documenting Python Code: A Complete Guide (source: Real Python)
# 13. CI/CD
ex. CI/CD with CircleCI (source: Real Python)
Just push your code to the git repository,
let an automated pipeline test, build, publish your package!
# 14. PYTHON PACKAGE PROJECT TEMPLATE
A tool that can be configured to include all best practices
and get started with your package in seconds!
# 15. REFERENCES
- Python.org:
- Python Packaging User Guide: https://packaging.python.org
- Module & Packages (tutorial chap. 6)
- Python Packaging Demystified (Bernàt, PyCon 2021)
- Publishing (Perfect) Python Packages on PyPi (Smith, EuroPython 2019)
- Python Packages by Beuzen & Timbers: https://py-pkgs.org/
- Codetiming: Good example of best practices in Python
- More complex setup: The Sheer Joy of Packaging! (multi-language)
- Python Modules and Packages by Real Python (Jan. 2020)
- Scripts, Modules, Packages, and Libraries by Real Python (May. 2020)